/*
 * Copyright 2013-2019 Xia Jun(3979434@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************************************
 *                                                                                     *
 *                        Website : http://www.farsunset.com                           *
 *                                                                                     *
 ***************************************************************************************
 */
package com.workcell.workdata.im.mvc.controller.user;

import com.workcell.workdata.im.annotation.*;
import com.workcell.workdata.im.component.event.LogoutEvent;
import com.workcell.workdata.im.constant.UserState;
import com.workcell.workdata.im.constant.ValidationCodeAction;
import com.workcell.workdata.im.entity.User;
import com.workcell.workdata.im.model.app.Origin;
import com.workcell.workdata.im.model.request.RegisterRequest;
import com.workcell.workdata.im.model.request.ResetPasswordRequest;
import com.workcell.workdata.im.model.response.ResponseEntity;
import com.workcell.workdata.im.model.vo.UserVO;
import com.workcell.workdata.im.service.AccessTokenService;
import com.workcell.workdata.im.service.UserService;
import com.workcell.workdata.im.service.ValidationCodeService;
import com.workcell.workdata.im.util.RandomPhone;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.util.DigestUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/user")
@Api(produces = "application/json", tags = "用户相关接口" )
@Validated
public class UserController {

	@Resource
	private UserService userService;

	@Resource
	private AccessTokenService accessTokenService;

	@Resource
	private ValidationCodeService validationCodeService;

	@Resource
	private ApplicationContext applicationContext;

	@ApiOperation(httpMethod = "GET", value = "通过手机号查询用户ID")
	@ApiImplicitParam(name = "telephone", value = "手机号", paramType = "path", dataTypeClass = String.class, required = true)
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "404" ,description = "手机号码不存在")
	})
	@GreenFunction
	@GetMapping(value = "/id/{telephone}")
	public ResponseEntity<Long> findId(@PathVariable String telephone) {

		Long id = userService.findId(telephone);

		if (id == null) {
			return ResponseEntity.make(HttpStatus.NOT_FOUND, "手机号码不存在");
		}

		return ResponseEntity.ok(id);
	}

	@ApiOperation(httpMethod = "GET", value = "通过手机号查询用户")
	@ApiImplicitParam(name = "telephone", value = "手机号", paramType = "path", dataTypeClass = String.class, required = true)
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "404" ,description = "手机号码不存在")
	})
	@GetMapping(value = "/find/{telephone}")
	public ResponseEntity<UserVO> get(@PathVariable String telephone) {
		User target = userService.findOne(telephone);
		if (target == null){
			return ResponseEntity.make(HttpStatus.NOT_FOUND, "手机号码不存在");
		}
		return ResponseEntity.ok(UserVO.of(target));
	}

	@ApiOperation(httpMethod = "GET", value = "查询单个用户信息")
	@ApiImplicitParam(name = "id", value = "ID", paramType = "path", dataTypeClass = String.class, required = true)
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "404" ,description = "UID不存在")
	})
	@GetMapping(value = "/{id}")
	public ResponseEntity<UserVO> get(@PathVariable long id) {
		User target = userService.findOne(id);
		if (target == null){
			return ResponseEntity.make(HttpStatus.NOT_FOUND, "UID不存在");
		}
		return ResponseEntity.ok(UserVO.of(target));
	}

	@ApiOperation(httpMethod = "GET", value = "查询多个用户信息")
	@ApiImplicitParam(name = "id",allowMultiple = true,value = "ID列表", paramType = "query", dataTypeClass = String.class, required = true)
	@GetMapping(value = "/list")
	public ResponseEntity<List<UserVO>> get(@RequestParam("id") List<Long> idList) {
		return ResponseEntity.ok(userService.findVoList(idList));
	}

	@ApiOperation(httpMethod = "GET", value = "批量查询用户名称")
	@ApiImplicitParam(name = "id",allowMultiple = true,value = "ID列表", paramType = "query", dataTypeClass = String.class, required = true)
	@GetMapping(value = "/name")
	public ResponseEntity<Map<Long,String>> getNameList(@RequestParam("id") List<Long> idList) {
		return ResponseEntity.ok(userService.findName(idList));
	}

	@ApiOperation(httpMethod = "POST", value = "登录")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "telephone", value = "手机号码", paramType = "query", dataTypeClass = String.class),
			@ApiImplicitParam(name = "password", value = "密码", paramType = "query", dataTypeClass = String.class),
	})
	@ApiResponses(value = {@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "404" ,description = "账号不存在"),
			@ApiResponse(responseCode = "423" ,description = "账号被禁用"),
			@ApiResponse(responseCode = "403" ,description = "密码不存在")})
	@GreenFunction
	@PostMapping(value = "/login")
	public ResponseEntity<UserVO> login(@ApiIgnore  @ClientOrigin Origin origin,
								   @RequestParam String telephone,
								   @RequestParam String password) {

		User user = userService.findOne(telephone);

		if (user == null) {
			return ResponseEntity.make(HttpStatus.NOT_FOUND.value(),"手机号码不存在");
		}

		if (user.getState() == UserState.DISABLED.getValue()) {
			return ResponseEntity.make(HttpStatus.LOCKED.value(),"该账号已经被禁用");
		}

		if (user.getState() == UserState.DESTROY.getValue()) {
			return ResponseEntity.make(HttpStatus.LOCKED.value(),"该账号已经被注销");
		}

		if (!BCrypt.checkpw(password.toUpperCase(),user.getPassword())) {
			return ResponseEntity.make(HttpStatus.FORBIDDEN.value(),"密码不正确");
		}

		ResponseEntity<UserVO> responseEntity = ResponseEntity.ok(UserVO.of(user));

		responseEntity.setToken(accessTokenService.generate(origin,user.getId()));

		return responseEntity;
	}


	@ApiOperation(httpMethod = "POST", value = "注册")
	@ApiResponses(value = {@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "409" ,description = "手机号码已经注册"),
			@ApiResponse(responseCode = "403" ,description = "验证码不正确")})
	@GreenFunction
	@PostMapping(value = "/register")
	@Validated(CreateAction.class)
	public ResponseEntity<UserVO> register(@ApiIgnore @ClientOrigin Origin origin,
									  @Valid @RequestBody RegisterRequest request) {

		if (userService.isExist(request.getTelephone())) {
			return ResponseEntity.make(HttpStatus.CONFLICT.value(),"该手机号码已经注册");
		}

		if (!validationCodeService.check(request.getTelephone(),request.getCode(), ValidationCodeAction.REGISTER)){
			return ResponseEntity.make(HttpStatus.FORBIDDEN.value(),"验证码不正确");
		}

		User user = new User();
		user.setName(request.getName());
		user.setTelephone(request.getTelephone());
		user.setPassword(request.getPassword());
		user.setState(UserState.NORMAL.getValue());

		userService.save(user);

		ResponseEntity<UserVO> responseEntity = ResponseEntity.ok(UserVO.of(user));

		responseEntity.setToken(accessTokenService.generate(origin,user.getId()));

		return responseEntity;
	}

	@ApiOperation(httpMethod = "POST", value = "注销账号")
	@PostMapping(value = "/unregister")
	@Validated(CreateAction.class)
	public ResponseEntity<Void> unregister(@ApiIgnore @UID long uid) {
		
		userService.destroy(uid);

		return ResponseEntity.ok();
	}

	@ApiOperation(httpMethod = "GET", value = "退出登录")
	@GetMapping(value = "/logout")
	public ResponseEntity<Void> logout(@ApiIgnore @ClientOrigin Origin origin,
									   @ApiIgnore @UID Long uid,
									   @ApiIgnore @AccessToken String token) {
		accessTokenService.delete(origin,token);
		applicationContext.publishEvent(new LogoutEvent(uid));
		return ResponseEntity.ok();
	}


	@ApiOperation(httpMethod = "PATCH", value = "修改名称")
	@ApiImplicitParam(name = "name", value = "名称", paramType = "query", dataTypeClass = String.class, required = true)
	@PatchMapping(value = "/name")
	public ResponseEntity<Void> updateName(@RequestParam String name, @ApiIgnore @UID Long uid) {
		userService.updateName(uid,name);
		return ResponseEntity.ok();
	}

	@ApiOperation(httpMethod = "PATCH", value = "个性签名")
	@ApiImplicitParam(name = "motto", value = "个性签名", paramType = "query", dataTypeClass = String.class, required = true)
	@PatchMapping(value = "/motto")
	public ResponseEntity<Void> updateMotto(@RequestParam String motto, @ApiIgnore @UID Long uid) {
		userService.updateMotto(uid,motto);
		return ResponseEntity.ok();
	}

	@ApiOperation(httpMethod = "PATCH", value = "修改密码")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "oldPassword", value = "旧密码(密文)", paramType = "query", dataTypeClass = String.class),
			@ApiImplicitParam(name = "newPassword", value = "新密码(密文)", paramType = "query", dataTypeClass = String.class),
	})
	@ApiResponses(value = {@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "403" ,description = "密码不正确")})
	@PatchMapping(value = "/password")
	public ResponseEntity<Void> password(@RequestParam String oldPassword, @RequestParam String newPassword, @ApiIgnore @UID Long uid) {


		if (!userService.checkPassword(uid,oldPassword.toUpperCase())) {
			return ResponseEntity.make(HttpStatus.FORBIDDEN.value(),"密码不正确");
		}

		userService.updatePassword(uid,newPassword.toUpperCase());
		return ResponseEntity.ok();
	}


	@ApiOperation(httpMethod = "POST", value = "重新设置密码")
	@ApiResponses(value = {@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "403" ,description = "验证码不正确"),
			@ApiResponse(responseCode = "404" ,description = "手机号码未注册")})
	@GreenFunction
	@PostMapping(value = "/forgot")
	@Validated(UpdateAction.class)
	public ResponseEntity<Void> forgot(@Valid @RequestBody ResetPasswordRequest request) {

		if (!validationCodeService.check(request.getTelephone(),request.getCode(), ValidationCodeAction.FORGOT)){
			return ResponseEntity.make(HttpStatus.FORBIDDEN.value(),"验证码不正确");
		}

		Long id = userService.findId(request.getTelephone());

		if (id == null){
			return ResponseEntity.make(HttpStatus.NOT_FOUND.value(),"手机号码未注册");
		}

		userService.updatePassword(id,request.getPassword());

		return ResponseEntity.ok();
	}




	@ApiOperation(httpMethod = "POST", value = "workdata注册")
	@ApiResponses(value = {@ApiResponse(responseCode = "200" ,description = "OK"),
			@ApiResponse(responseCode = "409" ,description = "手机号码已经注册"),
			@ApiResponse(responseCode = "403" ,description = "验证码不正确")})
	@GreenFunction
	@PostMapping(value = "/bindKey")
	@Validated(CreateAction.class)
	public ResponseEntity<UserVO> bindKey(@ApiIgnore @ClientOrigin Origin origin,
										  @RequestParam String bindKey,@RequestParam String name) {

		String phone = RandomPhone.generatePhoneNum();
		if (userService.isExist(phone)) {
			return ResponseEntity.make(HttpStatus.CONFLICT.value(),"该手机号码已经注册");
		}
		User u= userService.findbindKey(bindKey);
		if(null != u){
			return ResponseEntity.make(HttpStatus.CONFLICT.value(),"bindKey存在");
		}
		String md5 = DigestUtils.md5DigestAsHex("000000".getBytes(StandardCharsets.UTF_8));
		String password = BCrypt.hashpw(md5.toUpperCase(),BCrypt.gensalt(4));
		User user = new User();
		user.setName(name);
		user.setTelephone(phone);
		user.setPassword(password);
		user.setState(UserState.NORMAL.getValue());
		user.setBindKey(bindKey);
		userService.save(user);

		ResponseEntity<UserVO> responseEntity = ResponseEntity.ok(UserVO.of(user));

		responseEntity.setToken(accessTokenService.generateBindKey(origin,bindKey));

		return responseEntity;
	}




	@ApiOperation(httpMethod = "POST", value = "登录")
	@GreenFunction
	@PostMapping(value = "/loginWork")
	public ResponseEntity<UserVO> loginWork(@ApiIgnore  @ClientOrigin Origin origin,
										@RequestParam String bindKey
										) {

		User user = userService.findbindKey(bindKey);

		if (user == null) {
			return ResponseEntity.make(HttpStatus.NOT_FOUND.value(),"号码不存在");
		}

		if (user.getState() == UserState.DISABLED.getValue()) {
			return ResponseEntity.make(HttpStatus.LOCKED.value(),"该账号已经被禁用");
		}

		if (user.getState() == UserState.DESTROY.getValue()) {
			return ResponseEntity.make(HttpStatus.LOCKED.value(),"该账号已经被注销");
		}

		ResponseEntity<UserVO> responseEntity = ResponseEntity.ok(UserVO.of(user));

		responseEntity.setToken(accessTokenService.generate(origin,user.getId()));

		return responseEntity;
	}
}
